<?php


namespace App\Http\Service;


class Redisd
{

    //
    private static $redis;
    //redis连接
    private $conn;

    //私有构造函数
    private function __construct()
    {
        //连接本地redis
        $host = "127.0.0.1";
        $port = "6379";
        $this->conn = new \Redis();
        $this->conn->connect($host, $port);
    }

    //私有克隆方式
    private function __clone()
    {
        // TODO: Implement __clone() method.
    }

    //单一获取对象入口
    public static function getInstance()
    {
        //若部位该类对象则实例化对象，若不是则返回已实例化对象
        if (!self::$redis instanceof self) {
            self::$redis = new self;
        }
        return self::$redis;
    }

    /**
     * 查看当前库的全部键的数量
     * @return int 当前库key的数量
     */
    public function dbSize()
    {
        return $this->conn->dbSize();
    }

    /**
     * 切换redis的库
     * @param int $number 要切换的redis库
     * @return bool 是否成功
     */
    public function selectDb($number)
    {
        return $this->conn->select($number);
    }

    /**
     * 查看redis键的过期时间
     * @param $key 键
     * @return int 过期时间
     */
    public function ttl($key)
    {
        return $this->conn->ttl($key);
    }

    /**
     * 查看redis键的类型
     * @param string $key 键值
     * @return string 键值的类型
     */
    public function type($key)
    {
        return $this->conn->type($key);
    }

    /**
     * 查看redis当前库的全部键
     * @return array 全部的键数组
     */
    public function keys()
    {
        return $this->conn->keys('*');
    }

    /**
     * 给一个键设置过期时间
     * @param string $key 键
     * @param int $ttl 过期时间
     * @return bool 是否成功
     */
    public function expire($key, $ttl)
    {
        return $this->conn->expire($key, $ttl);
    }

    /**
     * 设置字符串的值
     * @param string $key
     * @param string $value key设置的值
     * @param int $expire key过期时间
     * @return bool 是否成功
     */
    public function set($key, $value, $expire = 0)
    {
        $value = is_array($value) ? json_encode($value) : $value;
        return $expire ? $this->conn->set($key, $value, $expire) : $this->conn->set($key, $value);
    }

    /**
     * 设置多个字符串的值
     * @param $keyValues array 键值对数组
     * @return bool 是否成功
     */
    public function mSet($keyValues)
    {
        foreach ($keyValues as $k => $v) {
            if (is_array($v)) {
                $values[$k] = json_encode($v);
            } else {
                $values[$k] = $v;
            }
        }
        return $this->conn->mset($values);
    }

    /**
     * 设置key的值
     * @param string $key key
     * @param string $value key设置的值
     * nx 存在该key时，是否进行操作，true就是进行更新操作，false就是不能进行操作
     * @return bool 是否成功
     */
    public function setNx($key, $value)
    {
        $value = is_array($value) ? json_encode($value) : $value;
        return $this->conn->setnx($key, $value);
    }

    /**
     * 获取key得值
     * @param string key 键
     * @return array|int|string 值
     */
    public function get($key)
    {
        $data = $this->conn->get($key);
        return json_decode($data) ? json_decode($data) : $data;
    }

    /**
     * 获取多个字符串类型键的值
     * @param $keys array 键的数组
     * @return array 键的值的数组
     */
    public function mGet($keys)
    {
        $data = $this->conn->mget($keys);
        foreach ($data as $k => $v) {
            if (json_decode($v)) {
                $res[$k] = json_decode($v);
            } else {
                $res[$k] = $v;
            }
        }
        return $res;
    }

    /**
     * 自增操作 每次加一
     * @param $key string
     * @return int 当前key的值
     */
    public function incr($key)
    {
        return $this->conn->incr($key);
    }

    /**
     * 自增指定长度 ,每次加指定长度
     * @param $key string 键
     * @param $step int 指定长度
     * @return int 当前key的值
     */
    public function incrBy($key, $step)
    {
        return $this->conn->incrBy($key, $step);
    }

    /**
     * 自减操作 每次减一
     * @param $key string
     * @return int 当前key的值
     */
    public function decr($key)
    {
        return $this->conn->decr($key);
    }

    /**
     * 自减指定长度 ,每次减指定长度
     * @param $key string 键
     * @param $step int 指定长度
     * @return int 当前key的值
     */
    public function decrBy($key, $step)
    {
        return $this->conn->decrBy($key, $step);
    }

    /**
     * 将value追加到原来key的值上
     * @param $key string 键
     * @param $value string 追加的值
     * @return int 当前key值的长度
     */
    public function append($key, $value)
    {
        return $this->conn->append($key, $value);
    }

    /**
     * 将该key的老value获取出来并设置新的value值
     * @param $key string 键
     * @param $value string 新的value
     * @return string|array 老的value
     */
    public function getSet($key, $value)
    {
        $value = is_array($value) ? json_encode($value) : $value;
        $res = $this->conn->getSet($key, $value);
        return json_decode($res) ? json_decode($res) : $res;
    }

    /**
     * 移除redis
     * @param string $key redis的键
     */
    public function del($key)
    {
        return $this->conn->del($key);
    }

    /**
     * 在list的左边插入数据
     * @param $key string 键
     * @param $value string 值
     * @return bool 是否成功
     */
    public function lPush($key, $value)
    {
        $value = is_array($value) ? json_encode($value) : $value;
        return $this->conn->lPush($key, $value);
    }

    /**
     * 在list的右边插入数据
     * @param $key string 键
     * @param $value string 值
     * @return bool 是否成功
     */
    public function rPush($key, $value)
    {
        $value = is_array($value) ? json_encode($value) : $value;
        return $this->conn->rPush($key, $value);
    }

    /**
     * 在list的右边弹出数据
     * @param $key string 键
     * @return string|array 右边弹出的值
     */
    public function rPop($key)
    {
        $res = $this->conn->rPop($key);
        return json_decode($res) ? json_decode($res) : $res;
    }

    /**
     * 在list的左边弹出数据
     * @param $key string 键
     * @return string|array 左边弹出的值
     */
    public function lPop($key)
    {
        $res = $this->conn->lPop($key);
        return json_decode($res) ? json_decode($res) : $res;
    }

    /**
     * lLen 获取list的长度
     * @param string $key
     * @return int list长度
     */
    public function lLen($key)
    {
        return $this->conn->lLen($key);
    }

    /**
     * ltrim 截取列表中的值
     * @param string $key 键
     * @param int $start 开始索引
     * @param int $end 结束索引
     * @return array
     */
    public function lTrim($key, $start, $end)
    {
        $res = $this->conn->lTrim($key, $start, $end);
        if (is_array($res)) {
            foreach ($res as $k => $v) {
                if (json_decode($v)) {
                    $res1[$k] = json_decode($v);
                } else {
                    $res1[$k] = $v;
                }
            }
        } else {
            $res1 = $res;
        }
        return $res1;
    }

    /**
     * lRange 获取list中的数据
     * @param string $key
     * @param int $start 开始索引
     * @param int $end 结束索引
     * @return array list中的数据
     */
    public function lRange($key, $start, $end)
    {
        $res = $this->conn->lRange($key, $start, $end);
        foreach ($res as $k => $v) {
            if (json_decode($v)) {
                $res1[$k] = json_decode($v);
            } else {
                $res1[$k] = $v;
            }
        }
        return $res1;
    }

    /**
     * rPopLPush 取出key1列表中的最后一个值，加入到key2列表中。
     * @param $key1 string 源列表的key
     * @param $key2 string 目标列表的key
     * @return string | array
     */
    public function rPopLPush($key1, $key2)
    {
        $res = $this->conn->rpoplpush($key1, $key2);
        $res = json_decode($res) ? json_decode($res) : $res;
        return $res;
    }

    /**
     * hSet 设置hash值
     * @param $key string  键
     * @param $field string  字段
     * @param $value string | array 值
     * @return bool 是否成功
     */
    public function hSet($key, $field, $value)
    {
        $value = is_array($value) ? json_encode($value) : $value;
        $res = $this->conn->hSet($key, $field, $value);
        return $res;
    }

    /**
     * hGet 获取hash值
     * @param $key string  键
     * @param $field string  字段
     * @return string|array 获取当前键、字段的值
     */
    public function hGet($key, $field)
    {
        $res = $this->conn->hGet($key, $field);
        return json_decode($res) ? json_decode($res) : $res;
    }

    /**
     * hMSet 设置hash多个field的值
     * @param $key string 键
     * @param $fieldsValues array  多个field=>value 数组
     * @return bool 是否成功
     */
    public function hMSet($key, $fieldsValues)
    {
        foreach ($fieldsValues as $k => $v) {
            if (is_array($v)) {
                $values[$k] = json_encode($v);
            } else {
                $values[$k] = $v;
            }
        }
        $res = $this->conn->hMSet($key, $values);
        return $res;
    }

    /**
     * hMGet 获取hash多个field的值
     * @param $key string 键
     * @param $fields array  多个字段数组
     * @return array 获取当前键、字段的值
     */
    public function hMGet($key, $fields)
    {
        $res = $this->conn->hMget($key, $fields);
        foreach ($res as $k => $v) {
            if (json_decode($v)) {
                $res1[$k] = json_decode($v);
            } else {
                $res1[$k] = $v;
            }
        }
        return $res1;
    }

    /**
     * hGetAll 获取key的全部field和value
     * @param $key string 键
     * @return array 全部的键值
     */
    public function hGetAll($key)
    {
        $data = $this->conn->hGetAll($key);
        foreach ($data as $k => $v) {
            $res[$k] = $v;
            if (json_decode($v)) {
                $res[$k] = json_decode($v);
            }
        }
        return $res;
    }

    /**
     * hDel 删除hash指定key的field
     * @param $key string
     * @param $field string
     * @return bool 是否成功
     */
    public function hDel($key, $field)
    {
        $this->conn->hDel($key, $field);
    }

    /**
     * hLen 获取hash指定key的field的数量
     * @param $key string
     * @return int
     */
    public function hLen($key)
    {
        $res = $this->conn->hLen($key);
        return $res;
    }

    /**
     * hExists 判断hash指定key的field是否存在
     * @param $key string
     * @param $field string
     * @return bool 是否存在
     */
    public function hExists($key, $field)
    {
        $res = $this->conn->hExists($key, $field);
        return $res;
    }

    /**
     * hKeys 获取hash当前key的全部field
     * @param $key string 键
     * @return array 全部的field
     */
    public function hKeys($key)
    {
        $res = $this->conn->hKeys($key);
        return $res;
    }

    /**
     * hValues 获取hash当前key的全部value
     * @param $key string 键
     * @return array 全部的values
     */
    public function hValues($key)
    {
        $res = $this->conn->hVals($key);
        return $res;
    }

    /**
     * hIncrBy 指定的key下指定的field自增长指定的step
     * @param $key string
     * @param $field string
     * @param $step int 自增长大小
     */
    public function hIncrBy($key, $field, $step)
    {
        $res = $this->conn->hIncrBy($key, $field, $step);
        return $res;
    }

    /**
     * sAdd 向指定的key的集合新增指定元素
     * @param $key string
     * @param $value array 集合值数组
     * @return int 成功插入的元素个数
     */
    public function sAdd($key, $value)
    {
        $return = 0;
        foreach ($value as $k => $v) {
            if (is_array($v)) {
                $res = $this->conn->sAdd($key, json_encode($v));
            } else {
                $res = $this->conn->sAdd($key, $v);
            }
            if ($res) {
                $return++;
            }
        }
        return $return;
    }

    /**
     * sMembers 获取指定集合的全部元素
     * @param $key string
     * @return array 全部元素
     */
    public function sMembers($key)
    {
        $res = $this->conn->sMembers($key);
        foreach ($res as $k => $v) {
            if (json_decode($v)) {
                $res1[$k] = json_decode($v);
            } else {
                $res1[$k] = $v;
            }
        }
        return $res1;
    }

    /**
     * sCard 返回指定集合全部的元素个数
     * @param string $key
     * @return int 元素个数
     */
    public function sCard($key)
    {
        $res = $this->conn->sCard($key);
        return $res;
    }

    /**
     * sRem 删除指定集合的指定元素
     * @param $key string
     * @param $value array 删除的元素集合
     * @return int 成功删除的个数
     */
    public function sRem($key, $value)
    {
        $return = 0;
        foreach ($value as $k => $v) {
            if (is_array($v)) {
                $res = $this->conn->sRem($key, json_encode($v));
            } else {
                $res = $this->conn->sRem($key, $v);
            }
            if ($res) {
                $return++;
            }
        }
        return $return;
    }

    /**
     * sPop 随机删除指定集合的元素
     * @param $key string
     * @param $count int 睡觉删除数量，默认为1
     * @return int 成功删除的个数
     */
    public function sPop($key, $count = 1)
    {
        $return = 0;
        for ($i = 0; $i < $count; $i++) {
            $res = $this->conn->sPop($key);
            if ($res) {
                $return++;
            }
        }
        return $return;
    }

    /**
     * sisMember 查看集合中指定key的元素是否存在
     * @param $key string 指定的key
     * @param $value string | array 指定的元素
     * @return bool 是否存在
     */

    public function sisMember($key, $value)
    {
        if (is_array($value)) {
            $value = json_encode($value);
        }
        $res = $this->conn->sIsMember($key, $value);
        return $res;
    }

    /**
     * sMove 把源集合中的value删除，并添加到目标集合中
     * @param $key1 string 源集合
     * @param $key2 string 目标集合
     * @param $value string | array 需要移动的元素
     * @return bool 移动是否成功
     */
    public function sMove($key1, $key2, $value)
    {
        if (is_array($value)) {
            $value = json_encode($value);
        }
        $res = $this->conn->sMove($key1, $key2, $value);
        return $res;
    }

    /**
     * sInter求出key1，key2 两个集合的交集
     * @param $key1 string 集合一
     * @param $key2 string 集合二
     * @return array 两个集合的交集
     */
    public function sInter($key1, $key2)
    {
        $res = $this->conn->sInter($key1, $key2);
        foreach ($res as $k => $v) {
            if (json_decode($v)) {
                $res1[$k] = json_decode($v);
            } else {
                $res1[$k] = $v;
            }
        }
        return $res1;
    }

    /**
     * sUnion 求出key1、key2两个集合之间的并集
     * @param $key1 string 集合一
     * @param $key2 string 集合二
     * @return array 两个集合的并集
     */
    public function sUnion($key1, $key2)
    {
        $res = $this->conn->sUnion($key1, $key2);
        foreach ($res as $k => $v) {
            if (json_decode($v)) {
                $res1[$k] = json_decode($v);
            } else {
                $res1[$k] = $v;
            }
        }
        return $res1;
    }

    /**
     * sDiff 求出key1、key2两个集合之间的差集，顺序不同，结果不同。
     * @param string $key1 集合一
     * @param string $key2 集合二
     * @return array 两个集合的差集
     */
    public function sDiff($key1, $key2)
    {
        $res = $this->conn->sDiff($key1, $key2);
        foreach ($res as $k => $v) {
            if (json_decode($v)) {
                $res1[$k] = json_decode($v);
            } else {
                $res1[$k] = $v;
            }
        }
        return $res1;
    }

    /**
     * zAdd 向有序集合指定key添加元素
     * @param $key string
     * @param $scoreValue array 分-值数组
     * @return int 成功添加元素个数
     */
    public function zAdd($key, $scoreValue)
    {
        $return = 0;
        foreach ($scoreValue as $k => $v) {
            if (is_array($v)) {
                $return = $this->conn->zAdd($key, $k, json_encode($v));
            } else {
                $return = $this->conn->zAdd($key, $k, $v);
            }
            $return++;
        }
        return $return;
    }

    /**
     * zRem 删除有序集合指定key的元素
     * @param string $key
     * @param string | array $value 删除有序集合中的指定值
     * @return int 成功删除的个数
     */
    public function zRem($key, $value)
    {
        $return = 0;
        foreach ($value as $k => $v) {
            if (is_array($v)) {
                $res = $this->conn->zRem($key, json_encode($v));
            } else {
                $res = $this->conn->zRem($key, $v);
            }
            if ($res) {
                $return++;
            }
        }
        return $value;
    }

    /**
     * zRange 获取指定有序集合的信息(从小到大)
     * @param $key string 有序集合的键
     * @param $start int 开始索引
     * @param $end int 结束索引
     * @param $withScore bool 查询到的集合的信息是否带source
     * @return array
     */
    public function zRange($key, $start, $end, $withScore = false)
    {
        $res = $this->conn->zRange($key, $start, $end, $withScore);
        if ($withScore) {
            foreach ($res as $k => $v) {
                if (json_decode($k)) {
                    $res1[$v] = json_decode($k);
                } else {
                    $res1[$v] = $k;
                }
            }
        } else {
            foreach ($res as $k => $v) {
                if (json_decode($v)) {
                    $res1[$k] = json_decode($v);
                } else {
                    $res1[$k] = $v;
                }
            }
        }
        return $res1;
    }

    /**
     * zRevRange 获取指定有序集合的信息(从大到小)
     * @param $key string 有序集合的键
     * @param $start int 开始索引
     * @param $end int 结束索引
     * @param $withScore bool 查询到的集合的信息是否带source
     * @return array
     */
    public function zRevRange($key, $start, $end, $withScore = false)
    {
        $res = $this->conn->zRevRange($key, $start, $end, $withScore);
        if ($withScore) {
            foreach ($res as $k => $v) {
                if (json_decode($k)) {
                    $res1[$v] = json_decode($k);
                } else {
                    $res1[$v] = $k;
                }
            }
        } else {
            foreach ($res as $k => $v) {
                if (json_decode($v)) {
                    $res1[$k] = json_decode($v);
                } else {
                    $res1[$k] = $v;
                }
            }
        }
        return $res1;
    }

    /**
     * zCard 获取指定key有序集合的元素数量
     * @param string $key
     * @return int
     */
    public function zCard($key)
    {
        $res = $this->conn->zCard($key);
        return $res;
    }

    /**
     * zScore 获取指定key指定value的score值
     * @param string $key
     * @param string $value
     * @return int
     */
    public function zScore($key, $value)
    {
        $res = $this->conn->zScore($key, $value);
        return $res;
    }

    /**
     * zCount 获取指定key的score区间的数量 [$min<=score<=$max]
     * @param string $key
     * @param int $min 最小score
     * @param int $max 最大score
     * @return int 区间的数量
     */
    public function zCount($key, $min, $max)
    {
        $res = $this->conn->zCount($key, $min, $max);
        return $res;
    }

    /**
     * zRemRangeByScore 删除指定key的score区间的value值
     * @param string $key
     * @param int $min 最小score
     * @param int $max 最大score
     * @return int
     */
    public function zRemRangeByScore($key, $min, $max)
    {
        $res = $this->conn->zRemRangeByScore($key, $min, $max);
        return $res;
    }

}
